package com.hkts.beltweigher.master.service.serviceimpl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hkts.beltweigher.master.entity.*;
import com.hkts.beltweigher.master.mapper.YbClassesAccumulateMapper;
import com.hkts.beltweigher.master.mapper.YbRunAccumulateMapper;
import com.hkts.beltweigher.master.service.IDisplaydataService;
import com.hkts.beltweigher.master.service.IRandomNumberSettingsService;
import com.hkts.beltweigher.master.service.IYbRunAccumulateService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hkts.beltweigher.master.vo.DateStatisticsVo;
import com.hkts.beltweigher.master.vo.ReportStatisticsResultVo;
import com.hkts.beltweigher.master.vo.RunDataStaticResultVo;
import com.hkts.beltweigher.master.vo.RunDataStaticVo;
import com.hkts.beltweigher.synchronizationtask.EnviromentConstance;
import com.hkts.beltweigher.utils.DateUtil;
import com.hkts.beltweigher.utils.Result;
import com.hkts.beltweigher.utils.ResultUtil;
import com.hkts.beltweigher.utils.SnowFlakeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.sql.Date;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hml
 * @since 2024-04-10
 */
@Service
@Transactional
public class YbRunAccumulateServiceImpl extends ServiceImpl<YbRunAccumulateMapper, YbRunAccumulate> implements IYbRunAccumulateService {


    @Autowired
    private YbRunAccumulateMapper ybRunAccumulateMapper;

    @Autowired
    private IRandomNumberSettingsService iRandomNumberSettingsService;

    @Autowired
    private IDisplaydataService iDisplaydataService;
    @Autowired
    private YbClassesAccumulateMapper ybClassesAccumulateMapper;

    @Override
    public IPage<YbRunAccumulate> selectPage(Page<YbRunAccumulate> page, YbRunAccumulate ybRunAccumulate) {
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        query.lambda().ge(ybRunAccumulate.getStartTime() != null, YbRunAccumulate::getStartTime, ybRunAccumulate.getStartTime())
                .le(ybRunAccumulate.getStartTime() != null, YbRunAccumulate::getStartTime, ybRunAccumulate.getEndTime())
                .orderByDesc(YbRunAccumulate::getStartTime);
        return ybRunAccumulateMapper.selectPage(page, query);
    }


    @Override
    public Result<Object> selectList(String startTime, String endTime) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        java.util.Date parse = format.parse(endTime);
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(parse);
        calendar.add(Calendar.DATE, 1);
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        query.lambda().ge(StringUtils.isNotBlank(startTime), YbRunAccumulate::getStartTime, startTime)
                .le(StringUtils.isNotBlank(endTime), YbRunAccumulate::getEndTime, calendar.getTime())
                .orderByDesc(YbRunAccumulate::getStartTime);

        List<YbRunAccumulate> ybRunAccumulates = ybRunAccumulateMapper.selectList(query);
        List<String> collect = ybRunAccumulates.stream().map(YbRunAccumulate::getInstrumentName).distinct().collect(Collectors.toList());
        List<RunDataStaticResultVo> result = new ArrayList<>();
        for (int i = 0; i < collect.size(); i++) {
            String instrumentName = collect.get(i);
            List<YbRunAccumulate> instrumentNameList = ybRunAccumulates.stream().filter(ybRunAccumulate -> ybRunAccumulate.getInstrumentName().equals(instrumentName)).collect(Collectors.toList());
            List<LocalDateTime> dateTimeList = instrumentNameList.stream().map(YbRunAccumulate::getStartTime).distinct().collect(Collectors.toList());
            RunDataStaticResultVo vo = new RunDataStaticResultVo();
            vo.setInstrumentName(instrumentName);
            List<RunDataStaticVo> dateStatisticsList = new ArrayList<>();
            for (int i1 = 0; i1 < dateTimeList.size(); i1++) {
                LocalDateTime localDateTime = dateTimeList.get(i1);
                List<YbRunAccumulate> data = ybRunAccumulates.stream().filter(ybRunAccumulate ->
                        ybRunAccumulate.getStartTime() == localDateTime && ybRunAccumulate.getInstrumentName().equals(instrumentName)).collect(Collectors.toList());
                RunDataStaticVo runDataStaticVo = new RunDataStaticVo();
                runDataStaticVo.setStartTime(localDateTime);
                runDataStaticVo.setStartValue(data.get(0).getStartValue());
                runDataStaticVo.setEndValue(data.get(0).getEndValue());
                runDataStaticVo.setTotalValue(data.get(0).getTotal());
                dateStatisticsList.add(runDataStaticVo);
            }
            vo.setList(dateStatisticsList);
            result.add(vo);
        }
        List<RunDataStaticResultVo> collect1 = result.stream()
                .sorted(Comparator.comparing(RunDataStaticResultVo::getInstrumentName))
                .collect(Collectors.toList());
        return ResultUtil.data(collect1);
    }

    @Override
    public YbRunAccumulate selectYbRunAccumulate(String instrumentName) {
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        query.lambda().eq(StringUtils.isNotBlank(instrumentName), YbRunAccumulate::getInstrumentName, instrumentName)
                .last("LIMIT 1").orderByDesc(YbRunAccumulate::getId);
        return ybRunAccumulateMapper.selectOne(query);
    }

    @Override
    public List<YbRunAccumulate> selectExportList(String startTime, String endTime) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        java.util.Date parse = format.parse(endTime);
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(parse);
        calendar.add(Calendar.DATE, 1);
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        query.lambda().ge(YbRunAccumulate::getStartTime, startTime)
                .le(YbRunAccumulate::getStartTime, format.format(calendar.getTime()))
                .orderByDesc(YbRunAccumulate::getStartTime);
        return ybRunAccumulateMapper.selectList(query);
    }

    @Override
    public List<YbRunAccumulate> selectBetweenList(Integer type) {
        LocalDateTime currentDateTime = LocalDateTime.now();
        LocalTime currentTime = LocalTime.now();
        LocalDateTime eightTime = LocalDateTime.of(currentDateTime.toLocalDate(), LocalTime.of(8, 0, 0));
        LocalDateTime twentyOClock = null;
        if (DateUtil.getBeforeEightTime(currentTime)) {
            twentyOClock = DateUtil.getBeforeEightDate();
        } else {
            twentyOClock = LocalDateTime.of(currentDateTime.toLocalDate(), LocalTime.of(20, 0, 0));
        }

        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        if (type == 1) {
            query.lambda().ge(YbRunAccumulate::getStartTime, eightTime)
                    .orderByAsc(YbRunAccumulate::getEndTime);
        } else {
            query.lambda().ge(YbRunAccumulate::getStartTime, twentyOClock)
                    .orderByAsc(YbRunAccumulate::getEndTime);
        }
        return ybRunAccumulateMapper.selectList(query);
    }

    @Override
    public Map<String, YbRunAccumulate> selectYbRunAccumulateByClass(Integer type) {
        LocalDate today = LocalDate.now(); // 当前日期
        LocalDate yesterday = today.minusDays(1); // 前一天
        LocalTime time = LocalTime.of(20, 0); // 晚上8点
        LocalDateTime yesterdayEvening8 = LocalDateTime.of(yesterday, time);
        LocalDateTime currentDateTime = LocalDateTime.now();
        LocalDateTime eightTime = LocalDateTime.of(currentDateTime.toLocalDate(), LocalTime.of(8, 0, 0));
        LocalDateTime twentyOClock = LocalDateTime.of(currentDateTime.toLocalDate(), LocalTime.of(20, 0, 0));
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        if (type == 1) {
            query.select("instrument_name as instrumentName,SUM(total) as total")
                    .ge(YbRunAccumulate.START_TIME, yesterdayEvening8)
                    .le(YbRunAccumulate.END_TIME, eightTime)
                    .groupBy(YbRunAccumulate.INSTRUMENT_NAME);
        } else {
            query.select("instrument_name as instrumentName,SUM(total) as total")
                    .ge(YbRunAccumulate.START_TIME, eightTime)
                    .le(YbRunAccumulate.END_TIME, twentyOClock)
                    .groupBy(YbRunAccumulate.INSTRUMENT_NAME);
        }
        List<YbRunAccumulate> ybRunAccumulates = ybRunAccumulateMapper.selectList(query);
        Map<String, YbRunAccumulate> collect = ybRunAccumulates.stream().collect(Collectors.toMap(YbRunAccumulate::getInstrumentName, Function.identity()));
        return collect;
    }


    @Override
    public void selectBetweenListByDate() {

        LocalDateTime startDate = LocalDateTime.of(2024, 4, 28, 8, 0);
        LocalDateTime endDate = LocalDateTime.of(2024, 7, 6, 8, 0);

        LocalDateTime current = startDate;

        while (current.isBefore(endDate)) {
            LocalDateTime startOfDay = current.withHour(8).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime endOfDay = current.withHour(20).withMinute(0).withSecond(0).withNano(0);
            System.out.println("From: " + startOfDay + " To: " + endOfDay);
            List<YbRunAccumulate> ybRunAccumulates = printDateRange(startOfDay, endOfDay);
            List<Float> floats = updateRunDataDefult(ybRunAccumulates, 1);

            LocalDateTime localDateTime = current.plusDays(1).withHour(8).withMinute(0).withSecond(0).withNano(0);
            System.out.println("From: " + endOfDay + " To: " + localDateTime);
            List<YbRunAccumulate> ybRunAccumulates1 = printDateRange(endOfDay, localDateTime);
            updateRunData(ybRunAccumulates1, 2,floats);



            LocalDateTime localDateTimeNext = current.plusDays(1).withHour(20).withMinute(0).withSecond(0).withNano(0);
            List<YbRunAccumulate> ybRunAccumulatesNext = printDateRange(localDateTime, localDateTimeNext);
            List<Float> floatNext = updateRunDataDefult(ybRunAccumulates1, 2);
            updateRunData(ybRunAccumulatesNext, 2,floatNext);

            current = current.plusDays(1);
        }

    }

    public List<YbRunAccumulate> printDateRange(LocalDateTime start, LocalDateTime end) {
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        query.lambda().ge(YbRunAccumulate::getStartTime, start)
                .le(YbRunAccumulate::getEndTime, end)
                .orderByAsc(YbRunAccumulate::getEndTime);
        return ybRunAccumulateMapper.selectList(query);
    }

    public void updateRunData(List<YbRunAccumulate> ybRunAccumulates, Integer type,List<Float> floats) {
        //排序
        Map<String, List<YbRunAccumulate>> collect = ybRunAccumulates.stream()
                .collect(Collectors.groupingBy(YbRunAccumulate::getInstrumentName));
        Map<String, List<YbRunAccumulate>> resultMap = new TreeMap<>(collect);
        List<YbRunAccumulate> ybRunAccumulateList = new ArrayList<>();
        YbRunAccumulate run1 = resultMap.get("中文仪表1").get(0);
        run1.setStartValue(floats.get(0));
        ybRunAccumulateList.add(run1);
        YbRunAccumulate run2 = resultMap.get("中文仪表2").get(0);
        run2.setStartValue(floats.get(1));
        ybRunAccumulateList.add(run2);
        YbRunAccumulate run3 = resultMap.get("中文仪表3").get(0);
        run3.setStartValue(floats.get(2));
        ybRunAccumulateList.add(run3);
        YbRunAccumulate run4 = resultMap.get("中文仪表4").get(0);
        run4.setStartValue(floats.get(3));
        ybRunAccumulateList.add(run4);
        YbRunAccumulate run5 = resultMap.get("中文仪表5").get(0);
        run5.setStartValue(floats.get(4));
        ybRunAccumulateList.add(run5);
        updateBatchById(ybRunAccumulateList);
    }


    public List<Float> updateRunDataDefult(List<YbRunAccumulate> ybRunAccumulates, Integer type) {
        //排序
        Map<String, List<YbRunAccumulate>> collect = ybRunAccumulates.stream()
                .collect(Collectors.groupingBy(YbRunAccumulate::getInstrumentName));
        Map<String, List<YbRunAccumulate>> resultMap = new TreeMap<>(collect);
        //获取随机数
        //RandomNumberSettings byId = iRandomNumberSettingsService.getById(type);

        //Float random = SnowFlakeUtil.getRandom(byId.getStartValue() * byId.getCoefficient(), byId.getEndValue() * byId.getCoefficient());
        //log.info("随机数为:{}", random);
        //计算所有数的总和
        List<Float> resultMapList = new ArrayList<>();
        /*double sum = ybRunAccumulates.stream()
                .flatMapToDouble(ybRunAccumulate -> DoubleStream.of(ybRunAccumulate.getTotal()))
                .sum();*/
        //求出比率
        for (Map.Entry<String, List<YbRunAccumulate>> entry : resultMap.entrySet()) {

            List<YbRunAccumulate> value = entry.getValue();
            for (int i = 0; i < value.size(); i++) {
                Float v1 = value.get(i).getTotal();
                value.get(i).setTotal(v1);
                value.get(i).setEndValue(value.get(i).getStartValue() + v1);
                if (i + 1 < value.size() && value.size() > 1) {
                    value.get(i + 1).setStartValue(value.get(i).getStartValue() + v1);
                }
            }
            resultMapList.add(value.get(value.size() -1 ).getEndValue());
            saveOrUpdateBatch(value);
        }
        return resultMapList;
    }

    @Override
    public void selectBetweenListClassByDate() {

        LocalDateTime startDate = LocalDateTime.of(2024, 11, 3, 8, 0);
        LocalDateTime endDate = LocalDateTime.of(2024, 11, 15, 8, 0);

        LocalDateTime current = startDate;

        while (current.isBefore(endDate)) {
            LocalDateTime startOfDay = current.withHour(8).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime endOfDay = current.withHour(20).withMinute(0).withSecond(0).withNano(0);
            System.out.println("From: " + startOfDay + " To: " + endOfDay);
            selectClassTotleByDate(startOfDay,endOfDay,1);

            LocalDateTime localDateTime = current.plusDays(1).withHour(8).withMinute(0).withSecond(0).withNano(0);
            System.out.println("From: " + endOfDay + " To: " + localDateTime);
            selectClassTotleByDate(endOfDay,localDateTime,2);

            current = current.plusDays(1);
        }

    }

    public void selectClassTotleByDate(LocalDateTime startTime,LocalDateTime endTime,Integer type){
        QueryWrapper<YbRunAccumulate> query = Wrappers.query();
        if (type == 1) {
            query.select("instrument_name as instrumentName,SUM(total) as total")
                    .ge(YbRunAccumulate.START_TIME, startTime)
                    .le(YbRunAccumulate.END_TIME, endTime)
                    .groupBy(YbRunAccumulate.INSTRUMENT_NAME);
        } else {
            query.select("instrument_name as instrumentName,SUM(total) as total")
                    .ge(YbRunAccumulate.START_TIME, startTime)
                    .le(YbRunAccumulate.END_TIME, endTime)
                    .groupBy(YbRunAccumulate.INSTRUMENT_NAME);
        }
        List<YbRunAccumulate> ybRunAccumulates = ybRunAccumulateMapper.selectList(query);
        Map<String, YbRunAccumulate> ybRunAccumulate = ybRunAccumulates.stream().collect(Collectors.toMap(YbRunAccumulate::getInstrumentName, Function.identity()));
        Displaydata displaydata = new Displaydata();
        List<Displaydata> displaydataList = iDisplaydataService.selectList(displaydata);
        List<YbClassesAccumulate> classesAccumulates = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        for (int i = 0; i < displaydataList.size(); i++) {
            if (displaydataList.get(i).getId() < 6) {
                YbClassesAccumulate ybClassesAccumulate = new YbClassesAccumulate();

                ybClassesAccumulate.setInstrumentName(displaydataList.get(i).getInstrumentName());
                if (type == 1){
                    ybClassesAccumulate.setDateTime(endTime.format(formatter));
                    ybClassesAccumulate.setStatisticsDate(Date.valueOf(endTime.toLocalDate()));
                    ybClassesAccumulate.setClasses(EnviromentConstance.CLASSES_ONE);
                    ybClassesAccumulate.setClassesName(EnviromentConstance.CLASSES_NAME_ONE);
                }else {
                    ybClassesAccumulate.setDateTime(startTime.format(formatter));
                    ybClassesAccumulate.setStatisticsDate(Date.valueOf(startTime.toLocalDate()));
                    ybClassesAccumulate.setClasses(EnviromentConstance.CLASSES_TWO);
                    ybClassesAccumulate.setClassesName(EnviromentConstance.CLASSES_NAME_TWO);
                }
                ybClassesAccumulate.setModifyTime(endTime);

                if(ybRunAccumulate.get(displaydataList.get(i).getInstrumentName()) != null){
                    ybClassesAccumulate.setClassesValue(ybRunAccumulate.get(displaydataList.get(i).getInstrumentName()).getTotal());
                } else {
                    ybClassesAccumulate.setClassesValue(0.0f);
                }

                classesAccumulates.add(ybClassesAccumulate);
            }
        }
        if (classesAccumulates.size() > 0) {
            ybClassesAccumulateMapper.batchInsert(classesAccumulates);
        }
    }


}
